<?php

namespace App\Http\Controllers;

use App\Common\PaySuccess;
use App\Http\Resources\CoinRecords;
use App\Http\Resources\Payment as PaymentResource;
use App\Http\Resources\Payments;
use App\Models\Coin;
use App\Models\Payment;
use App\Models\ThirdPartyUser;
use App\Services\WeChat;
use EasyWeChat\Payment\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;

class PaymentsController extends Controller
{
    /**
     * 支付单列表
     *
     * @return Payments
     */
    public function index()
    {
        $payments = Payment::where([
            'user_id' => Auth::id(),
            'status' => Payment::STATUS_PAID,
        ])->orderByDesc('id')->simplePaginate(per_page());

        return new Payments($payments);
    }

    /**
     * 生成支付交易单号
     *
     * @param Request $request
     * @return \App\Http\Resources\Payment
     */
    public function store(Request $request)
    {
        $user = $request->user();

        /** @var \App\Models\Coin $coin */
        $coin = Coin::findOrFail($request->post('coin_id'));
        if (! $coin->enable() || $coin->money < 0.01) {
            return invalidation('非法的充值金额');
        }

        // 创建交易单
        $payment = $this->createPayment($user, $coin);

        return new PaymentResource($payment);
    }

    /**
     * 获取支付配置参数
     *
     * @param \App\Models\Payment $payment
     * @param \App\Services\WeChat $wechat
     * @return array|\Illuminate\Http\JsonResponse
     */
    public function prepayParams(Payment $payment, WeChat $wechat)
    {
        $userId = Auth::id();

        // 权限验证
        if ($payment->isPaid() || $payment->user_id != $userId) {
            return access_denied();
        }
    
        if (app_client(['android', 'ios'])) {
            $openType = ThirdPartyUser::TYPE_WX_MOBILE;
            $tradeType = 'APP';
            $wxPayment = $wechat->mobileApp()->payment;
        } else {
            $openType = ThirdPartyUser::TYPE_WX_OFFICIAL;
            $tradeType = 'JSAPI';
            $wxPayment = $wechat->officialAccount()->payment;
        }

        // 获取微信用户相应的 openid
        $openid = ThirdPartyUser::where(['user_id' => $userId, 'type' => $openType])->value('openid');

        // 微信支付
        $attributes = [
            'trade_type' => $tradeType,
            'out_trade_no' => $payment->trade_no,
            'body' => '游戏币充值',
            'detail' => '',
            'total_fee' => intval(round($payment->money, 2) * 100),
            'openid' => $openid,
        ];

        $order = new Order($attributes);
        
        $result = $wxPayment->prepare($order);

        if ($result->return_code != 'SUCCESS' || $result->result_code != 'SUCCESS') {
            $errors = object_only($result, ['return_msg', 'err_code_des']);
            return invalidation(implode('。', $errors));
        }

        // 支付参数
        if ('APP' == $tradeType) {
            $config = $wxPayment->configForAppPayment($result->prepay_id);
        } else {
            $config = $wxPayment->configForJSSDKPayment($result->prepay_id);
        }

        return $this->wrapData($config);
    }

    /**
     * 交易单号查询
     *
     * @param  Payment $payment
     * @return \Illuminate\Http\JsonResponse|Resource
     */
    public function show(Payment $payment)
    {
        if ($payment->user_id != Auth::id()) {
            return access_denied();
        }

        return new PaymentResource($payment);
    }

    /**
     * 支付回调
     *
     * @param string $tradeType 支付类型:app, jsapi ，已配置在支付回调地址上
     * @param \App\Services\WeChat $wechat
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @throws \EasyWeChat\Core\Exceptions\FaultException
     */
    public function update($tradeType, WeChat $wechat)
    {
        if ('app' == $tradeType) {
            $wxPayment = $wechat->mobileApp()->payment;
        } else {
            $wxPayment = $wechat->officialAccount()->payment;
        }
        
        $response = $wxPayment->handleNotify(function ($notify, $successful) {
            log_info('payment/callback.log', json_encode($notify) . '|' . $successful);
            do {
                $payment = Payment::where('trade_no', $notify->out_trade_no)->first();

                if (!$payment) {
                    $error = '交易单号不存在';
                    break;
                }
                if (!$successful) {
                    $error = '支付未成功';
                    break;
                }

                $paySuccess = new PaySuccess();
                $result = $paySuccess->process($payment);

                return true === $result;
            } while (false);
            
            // 记录错误
            log_info('payment/callback.error.log', $error . '|' . json_encode($notify) . '|' . $successful);
            return true;
        });

        return $response;
    }

    /**
     * 获取充值列表
     *
     * @return array
     */
    public function coins()
    {
        $coins = Coin::where('status', Coin::STATUS_ENABLE)->orderByDesc('stick_time')->orderByDesc('id')->get();
        
        $data = $coins->map(function ($coin) {
            return [
                'id' => $coin->id,
                'coin' => $coin->coin,
                'coin_award' => $coin->coin_award,
                'money' => $coin->money,
            ];
        });
        
        return $this->wrapData($data);
    }

    /**
     * 游戏币流水记录
     *
     * @param Request $request
     * @return CoinRecords
     */
    public function coinRecords(Request $request)
    {
        $user = $request->user();

        $paginate = $user->coinRecords()->orderByDesc('id')->simplePaginate(per_page());

        return new CoinRecords($paginate);
    }

    /**
     * 模拟购买游戏币
     *
     * @param Request $request
     * @return PaymentResource|\Illuminate\Http\JsonResponse
     */
    public function fakePay(Request $request)
    {
        // 非生产环境，且开启模拟支付，才能进行模拟支付
        if (App::environment('production') || !config('mall.fake_pay')) {
            return access_denied();
        }

        $user = $request->user();

        /** @var \App\Models\Coin $coin */
        $coin = Coin::findOrFail($request->post('coin_id'));
        if (! $coin->enable() || $coin->money < 0.01) {
            return invalidation('非法的充值金额');
        }

        // 创建交易单
        $payment = $this->createPayment($user, $coin);

        $paySuccess = new PaySuccess();
        $paySuccess->process($payment);

        return new PaymentResource($payment);
    }
    
    /**
     * 创建购买游戏币交易单
     *
     * @param \App\Models\User $user
     * @param \App\Models\Coin $coin
     * @return \App\Models\Payment
     */
    private function createPayment($user, $coin)
    {
        return Payment::create([
            'trade_no' => $user->randomTradeNo(),
            'user_id' => $user->id,
            'status' => Payment::STATUS_UNPAID, // 未支付
            'coin' => $coin->coin + $coin->coin_award,
            'money' => $coin->money,
            'payable_type' => Payment::TYPE_COIN,
            'payable_id' => $coin->id,
            'source' => app_client(),    // 记录来源
        ]);
    }
}
